package com.rt.easyjava.base.modules.timerjob.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.rt.easyjava.base.modules.timerjob.bean.TmptTimerBiz;
import com.rt.easyjava.base.modules.timerjob.config.QuartzManager;
import com.rt.easyjava.base.modules.timerjob.dto.TmptTimerBizDto;
import com.rt.easyjava.base.modules.timerjob.mapper.ProcedureMapper;
import com.rt.easyjava.base.modules.timerjob.mapper.TmptTimerBizMapper;
import com.rt.easyjava.base.modules.timerjob.service.impl.base.TmptTimerServiceImpl;
import com.rt.easyjava.base.modules.timerjob.service.intf.TmptTimerBizService;
import com.rt.easyjava.base.modules.timerjob.service.job.SpringJobBean;
import com.rt.easyjava.base.modules.timerjob.service.job.jobStrategy.JobStrategy;
import com.rt.easyjava.base.modules.timerjob.service.job.jobStrategy.JobStrategyFactory;
import com.rt.easyjava.common.base.Result;
import com.rt.easyjava.common.config.dozer.MyMapper;
import com.rt.easyjava.common.enums.TimerIsActivity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * 服务实现类
 *
 * @author wuxiaoyong
 * @since 2020-06-01
 */
@Service(value = "tmptTimerService")
@Transactional
public class TmptTimerBizServiceImpl extends TmptTimerServiceImpl implements TmptTimerBizService {
    private final Logger logger = LoggerFactory.getLogger(TmptTimerBizServiceImpl.class);

    @Autowired
    private MyMapper mapper;
    @Resource
    private TmptTimerBizMapper tmptTimerBizMapper;
    @Resource
    private QuartzManager quartzManager;

    public static final String Job_Name_Pre = "job-";
    public static final String Job_Group_Name_Pre = "jobGroup-";
    public static final String Trigger_Name_Pre = "trigger-";
    public static final String Trigger_Group_Pre = "triggerGroup-";

    @Resource
    private ProcedureMapper procedureMapper;

    /**
     * 执行一次
     * @param tmptTimerBizDto
     * @return
     */
    @Override
    public synchronized Result<TmptTimerBizDto> executeOnce(TmptTimerBizDto tmptTimerBizDto) {
        // 执行Job策略
        JobStrategy jobStrategy = JobStrategyFactory.getJobStrategy(tmptTimerBizDto);
        return jobStrategy.execute();
    }

    /**
     * 动态调用存储过程
     *
     * @param procName
     * @param parmMap
     * @return
     */
    public Result callProc(String procName, Map parmMap) {
        try {
            List paramList = Arrays.asList(parmMap.values().toArray());
            if (paramList.size() == 0) {
                procedureMapper.call0(procName);
            }
            if (paramList.size() == 1) {
                procedureMapper.call1(procName, (String) paramList.get(0));
            }
            if (paramList.size() == 2) {
                procedureMapper.call2(procName, (String) paramList.get(0), (String) paramList.get(1));
            }
            if (paramList.size() == 3) {
                procedureMapper.call3(procName, (String) paramList.get(0), (String) paramList.get(1), (String) paramList.get(2));
            }
            if (paramList.size() == 4) {
                procedureMapper.call4(procName, (String) paramList.get(0), (String) paramList.get(1), (String) paramList.get(2), (String) paramList.get(3));
            }
            if (paramList.size() == 5) {
                procedureMapper.call5(procName, (String) paramList.get(0), (String) paramList.get(1), (String) paramList.get(2), (String) paramList.get(3), (String) paramList.get(4));
            }
        }catch (Exception e) {
            return Result.builder().fault(e.getLocalizedMessage());
        }
        return Result.builder();
    }

    // ==================================================================================
    // ========== 以下使用的是 Mybatis-plus 实现, 适合单表操作 ==============================
    // ==================================================================================

    /**
     * create a object
     *
     * @param tmptTimerBizDto
     * @return
     */
    @Override
    public Result<TmptTimerBizDto> create(TmptTimerBizDto tmptTimerBizDto) {
        // dto to entity
        TmptTimerBiz tmptTimerBiz = mapper.map(tmptTimerBizDto, TmptTimerBiz.class);
        // create a data
        tmptTimerBiz.insert();

        // 判断是否启动任务
        // 如果只添加一个暂停的任务，则不管它了，等修改记录时加入quartz
        if (TimerIsActivity.Pause.getId().equals(tmptTimerBiz.getTimerIsActivity())) {
            return Result.builder();
        }
        // 加入quartz
        try {
            tmptTimerBizDto.setId(tmptTimerBiz.getId()); // 做日志记录用
            addJob(tmptTimerBizDto, tmptTimerBiz.getId());
        } catch (ClassNotFoundException e) {
            log.error(e.getLocalizedMessage());
            return Result.builder().fault(e.getMessage());
        }

        return Result.builder();
    }

    /**
     * update a object by Id
     *
     * @param tmptTimerBizDto
     * @param updateWrapper
     * @return
     */
    @Override
    public synchronized Result<TmptTimerBizDto> update(TmptTimerBizDto tmptTimerBizDto, UpdateWrapper updateWrapper) {
        // dto to entity
        TmptTimerBiz tmptTimerBiz = mapper.map(tmptTimerBizDto, TmptTimerBiz.class);
        // update
        tmptTimerBizMapper.update(tmptTimerBiz, updateWrapper);

        // 判断是否启动任务
        String jobName = Job_Name_Pre + tmptTimerBiz.getId();
        String jobGroup = Job_Group_Name_Pre + tmptTimerBiz.getId();
        String triggerName = Trigger_Name_Pre + tmptTimerBiz.getId();
        String triggerGroup = Trigger_Group_Pre + tmptTimerBiz.getId();
        // 先删除任务
        quartzManager.removeJob(jobName, jobGroup, triggerName, triggerGroup);

        // 启动任务
        if (TimerIsActivity.Run.getId().equals(tmptTimerBiz.getTimerIsActivity())) {
            try {
                tmptTimerBizDto.setId(tmptTimerBiz.getId()); // 做日志记录用
                addJob(tmptTimerBizDto, tmptTimerBiz.getId());
            } catch (ClassNotFoundException e) {
                log.error(e.getLocalizedMessage());
                return Result.builder().fault(e.getMessage());
            }
        }

        return Result.builder();
    }



    /**
     * className 有以下三种情况，通过分析字符串来判断是哪种情况:
     * 1, com.rt.ej.quart.job.MyJobBean
     * 2, quartzService.test()
     * 3, http://resource-base/coding/test
     *
     * @param tmptTimerBizDto
     * @param id
     * @throws ClassNotFoundException
     */
    private void addJob(TmptTimerBizDto tmptTimerBizDto, Long id) throws ClassNotFoundException {
        String jobName = Job_Name_Pre + id;
        String jobGroup = Job_Group_Name_Pre + id;
        String triggerName = Trigger_Name_Pre + id;
        String triggerGroup = Trigger_Group_Pre + id;
        Result resultIsQuartzBean = isQuartzBean(tmptTimerBizDto.getClassName());

        if (resultIsQuartzBean.isSuccess()) {
            quartzManager.addJob(
                    tmptTimerBizDto,
                    jobName, jobGroup, triggerName, triggerGroup,
                    Class.forName(tmptTimerBizDto.getClassName()),
                    tmptTimerBizDto.getExpression());
        }
        // spring object or http remote
        else {
            quartzManager.addJob(
                    tmptTimerBizDto,
                    jobName, jobGroup, triggerName, triggerGroup,
                    SpringJobBean.class,
                    tmptTimerBizDto.getExpression());
        }
    }

    /**
     * className 有以下三种情况，通过分析字符串来判断是哪种情况:
     * 1, com.rt.ej.quart.job.MyJobBean
     * 2, quartzService.test()
     * 3, http://resource-base/coding/test
     *
     * @param className
     * @return
     */
    private Result isQuartzBean(String className) {
        // quartzService.test()
        if (className.endsWith("()")) {
            return Result.builder().fault();
        }
        // call proc()
        if (className.startsWith("call ")) {
            return Result.builder().fault();
        }
        // http://resource-base/coding/test
        else if (className.startsWith("http:") || className.startsWith("https:")) {
            return Result.builder().fault();
        }
        // com.rt.ej.quart.job.MyJobBean
        else {
            return Result.builder().success();
        }
    }

    /**
     * 分页 (无合计功能)
     *
     * @param page
     * @param queryWrapper
     * @return
     */
    public Result<TmptTimerBizDto> page(Page<TmptTimerBiz> page, QueryWrapper<TmptTimerBiz> queryWrapper) {
        return super.page(page, queryWrapper);
    }

    /**
     * select all by queryWrapper
     *
     * @param queryWrapper
     * @return
     */
    @Override
    public Result<TmptTimerBizDto> selectBy(QueryWrapper<TmptTimerBiz> queryWrapper) {
        return super.selectBy(queryWrapper);
    }

    /**
     * select one by id
     *
     * @param id
     * @return
     */
    @Override
    public Result<TmptTimerBizDto> selectById(Long id) {
        return super.selectById(id);
    }


    public Result<TmptTimerBizDto> selectById(Map map) {
        logger.info("----- selectById ---parma map: " + map);
        return Result.builder();
    }


    // ==================================================================================
    // ========== 以下使用的是自定义的 mapper.xml 实现, 适合多表查询 =========================
    // ==================================================================================

    /**
     * 分页查询：mybatis plus 自定义sql分页查询
     * 默认开启合计查询，按需注掉代码
     *
     * @param page
     * @param queryWrapper
     * @return
     */
    @Override
    public Result<TmptTimerBizDto> myPage(Page<TmptTimerBiz> page, QueryWrapper<TmptTimerBiz> queryWrapper) {
        return super.myPage(page, queryWrapper);
    }

    @Override
    public Result<TmptTimerBizDto> mySelectBy(QueryWrapper<TmptTimerBiz> queryWrapper) {
        return super.mySelectBy(queryWrapper);
    }

    @Override
    public Result<TmptTimerBizDto> mySelectById(long id) {
        return super.mySelectById(id);
    }

}
